package com.zoe.onelink.actuate.metrics.http;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
import okhttp3.Dispatcher;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.util.Assert;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;

import static com.zoe.onelink.common.constant.OnelinkMetricsConstant.HttpClient;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2022</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2022-06-20
 */
public class HttpClientMetricsInterceptor implements Interceptor {

    public HttpClientMetricsInterceptor(Dispatcher dispatcher) {
        Assert.notNull(dispatcher, "OkHttp dispatcher could not be null");
        Metrics.gauge(HttpClient.MAX_REQ_PER_HOST_SIZE, dispatcher.getMaxRequestsPerHost());
        Metrics.gauge(HttpClient.MAX_REQ_SIZE, dispatcher.getMaxRequests());
        Metrics.gauge(HttpClient.REQ_RUNNING_COUNT, dispatcher, Dispatcher::runningCallsCount);
        Metrics.gauge(HttpClient.REQ_QUEUE_TASK_COUNT, dispatcher, Dispatcher::queuedCallsCount);
        ExecutorService executorService = dispatcher.executorService();
        if (executorService instanceof ThreadPoolExecutor) {
            ThreadPoolExecutor executor = (ThreadPoolExecutor) executorService;
            Metrics.gauge(HttpClient.MAX_POOL_SIZE, executor, ThreadPoolExecutor::getMaximumPoolSize);
            Metrics.gauge(HttpClient.CORE_POOL_SIZE, executor, ThreadPoolExecutor::getCorePoolSize);
            Metrics.gauge(HttpClient.ACTIVE_POOL_COUNT, executor, ThreadPoolExecutor::getActiveCount);
            Metrics.gauge(HttpClient.LARGEST_POOL_SIZE, executor, ThreadPoolExecutor::getLargestPoolSize);
        }
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Timer.Sample sample = Timer.start(Metrics.globalRegistry);
        Request request = chain.request();
        Response response = null;
        try {
            response = chain.proceed(request);
        } finally {
            String threadName = Thread.currentThread().getName();
            boolean async = StrUtil.startWith(threadName, "okhttp", true);
            Timer timer = Metrics.timer(HttpClient.RESP_TIME,
                    "method", request.method(),
                    "status", String.valueOf(response == null ? "-1" : response.code()),
                    "uri", URLUtil.getPath(request.url().toString()),
                    "async", async + ""
            );
            sample.stop(timer);
        }
        return response;
    }

}
